using System;
using System.Reflection;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Proxies;

namespace Be.Timvw.Framework.Proxies
{
    public class LazyProxy<TResult, T> : RealProxy
    {
        private readonly Func<TResult, T> func;
        private readonly T funcParameter;
        private bool deferred;
        private TResult funcResult;
        private Type funcResultType;

        public LazyProxy(Func<TResult, T> func, T funcParameter)
        : base(typeof(TResult))
        {
            this.func = func;
            this.funcParameter = funcParameter;
            this.deferred = true;
        }

        public TResult ResultProxy
        {
            get { return (TResult) this.GetTransparentProxy(); }
        }

        public override IMessage Invoke(IMessage msg)
        {
            if(this.deferred)
            {
                this.funcResult = this.func(this.funcParameter);
                this.funcResultType = this.funcResult.GetType();
                this.deferred = false;
            }

            IMethodCallMessage callMsg = (IMethodCallMessage) msg;
            object result = this.funcResultType.InvokeMember(callMsg.MethodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.InvokeMethod, null, this.funcResult, callMsg.Args);
            return new ReturnMessage(result, null, 0, callMsg.LogicalCallContext, callMsg);
        }
    }
}